#include "StdAfx.h"
#include "ScriptEditorCompiler.h"
#include "ScriptLogOutput.h"
#include "ScriptEditorWidget.h"
#include <LitEditorInstance.h>

namespace Lit
{
	namespace Editor
	{
		/*/////////////////////////////////////
					SCRIPT
		/////////////////////////////////////*/
		ScriptCompiler::ScriptCompiler( InstancePtr inst ) 
		{
			mInstance = inst;
			mEngine = new ScriptEngine( inst->getRenderWidget()->ogreSceneManager(), *inst->getLogger()->data() );
			mInstance->getLogger()->clear();
			mInstance->getLogger()->logMessage( "Compiler Ready !" );
		}

		ScriptCompiler::~ScriptCompiler(void)
		{
			mEngine.destroy();
		}
		
		const ScriptEnginePtr& ScriptCompiler::getEngine() const{ return mEngine; }
		
		LoggerPtr ScriptCompiler::getLog() { return mInstance->getLogger(); }

		const InstancePtr& ScriptCompiler::getInstance() const{ return mInstance; }
		InstancePtr& ScriptCompiler::getInstance() { return mInstance; }

		void ScriptCompiler::compile( ScriptModulePtr module, ScriptEditorWidgetPtr edit, bool throww )
		{
			std::vector<ScriptEditorWidgetPtr> v;
			v.push_back( edit );
			compile( module, v, throww );
		}
		void ScriptCompiler::run( const std::string &module_name, const std::string &entry_point, ScriptEditorWidgetPtr edit )
		{
			
			std::vector<ScriptEditorWidgetPtr> v;
			v.push_back( edit );
			run( module_name, entry_point, v );
		}

		void ScriptCompiler::compile( ScriptModulePtr module, const std::vector<ScriptEditorWidgetPtr>& edit, bool throww )
		{
			module->clearIncludes();
			getLog()->clear();
			getLog()->logMessage("Building "+module->getName()+" ...");
			try
			{
				for( auto i=edit.begin(); i!=edit.end(); i++ )
				{
					getLog()->logMessage("\tCompiling script "+i->get()->getPath().fileName() );
					try
					{
						int r = module->addSection( i->get()->getPath().fileName(), i->get()->getText() );
						if( r < 0 ){
							std::string str = "Cannot add section "+i->get()->getPath().fileName()+ " to module "+module->getName();
							if( throww ) throw std::runtime_error(str.c_str());
							else getLog()->logMessage( std::string("\t\t")+str );
						}
						r = module->build();
						if( r < 0 ) 
						{
							std::string str = "Cannot build script "+i->get()->getPath().fileName()+ " in module "+module->getName();
							if( throww ) throw std::runtime_error(str.c_str());
							else getLog()->logMessage( std::string("\t\t")+str );
						}
						getLog()->logMessage( "Success" );
						if( mSuccess ) mSuccess( module );
					}
					catch( std::exception & e )
					{
						if( mError ) mError( module, e.what() );
						if( throww ) throw;
						else getLog()->logMessage( std::string("\t\t")+e.what() );
					}
					catch( ... ){
						if( mError ) mError( module, "unknown error" );

						if( throww ) throw;
						else getLog()->logMessage( std::string("\t\t")+std::string("unknown error") );  
					}
				}
			}
			catch( std::exception & e )
			{
					if( throww ) throw;
					else getLog()->logMessage( std::string("\t")+e.what() );
			}
			catch( ... ){ 
				if( throww ) throw;			
				else getLog()->logMessage( std::string("\tunknown error") );
			}
		}
		void ScriptCompiler::run( const std::string &module_name, const std::string &entry_point, const std::vector<ScriptEditorWidgetPtr>& edit )
		{
			getLog()->clear();
			try
			{
				ScriptModulePtr module(mEngine->createModule( module_name, SMF_ALWAYS_CREATE ));
				compile( module, edit, true );
				getLog()->logMessage( "Running module "+module_name+" with timeout "+String(mEngine->getTimeOut()).str() );
				ScriptContextPtr ctx(mEngine->nextFreeContext());
				ScriptContextState state = module->execute( entry_point, ctx );
				while( state == asEXECUTION_SUSPENDED )
				{
					getLog()->logMessage("\tReached timeout !");
					int ans = QMessageBox::question( NULL, "TimeOut", "The script got suspended due to timeout do you want to let it run another cycle ?", QMessageBox::Yes|QMessageBox::No );
					if( ans == QMessageBox::Yes ){
						getLog()->logMessage("\tResuming...");
						state = ScriptEngine::runTimeOut( ctx, mEngine->getTimeOut() );
					}
					else if( ans == QMessageBox::No )
					{
						int c=ctx->data()->Abort();
						state = SCS_EXECUTION_ABORTED;
						getLog()->logMessage("\tHalted: "+String(c).str());
						break;
					}
				}
				
				getLog()->logMessage( "Last Run Successful !" );
				getLog()->logMessage("Execution State is now "+ScriptContext::trExecutionState( state ));
				mEngine->releaseModule( module );
			}
			catch( std::exception & e )
			{
				getLog()->logMessage(std::string("\t")+e.what());
			}
			catch( ... ){ getLog()->logMessage("\tunknown error"); }
		}
	};
};